import { GRAPH_TYPES } from './Graph.enum';
import Point from '../Point';
// import * as geolib from 'geolib';

let GID = 0;
/**
 * Base class of Graph.
 */

export default class Base {
    constructor({
        ctx,
        ctxWidth,
        ctxHeight,
        ratio,
        pos,
        points,
        lineWidth,
        strokeStyle,
        fillStyle,
        radius,
        scaling
    } = {}) {
        // console.warn(...arguments);
        this.ctx = ctx;
        this.ctxWidth = ctxWidth;
        this.ctxHeight = ctxHeight;
        this.ratio = ratio || 2;
        this.x = pos.x;
        this.y = pos.y;
        this.h = 0;
        this.points = points || [];
        this.sides = 5;
        this.stars = 5;
        this.lineWidth = lineWidth || 50;
        this.strokeStyle = strokeStyle || '#000000';
        this.fillStyle = fillStyle || '';
        if (this.fillStyle === 'none') this.fillStyle = '';
        this.isFill = false;
        this.radius = radius || 10;
        this.scaling = scaling;
        this.isReverse = !scaling ? false : true;
        this.complete = true;
        // this.id = Date.now();
        this.id = 'BASE_ID_' + GID++;
        this.name = 'BASE';
        this.anchorIndex = -1;
        this.connectIndexs = [];
    }
    inject(ctx, scaling) {
        this.ctx = ctx;
        this.scaling = scaling;
        this.isReverse = !scaling ? false : true;
    }

    initControlPoints() {
        if (!this.points || !this.points.length) return;
        // let x = 0,
        //     y = 0;
        // this.points.forEach(p => {
        //     x += parseInt(p.x);
        //     y += parseInt(p.y);
        // });
        // this.x = Math.round(x / this.points.length);
        // this.y = Math.round(y / this.points.length);

        // let ll = [];
        // this.points.forEach(p => ll.push({ latitude: p.x, longitude: p.y }));
        // // let p = geolib.getCenterOfBounds(ll);
        // let p = geolib.getCenter(ll);
        // this.x = p.latitude;
        // this.y = p.longitude;
        // console.log('[Base] initControlPoints: ', this.id, ll, p);

        let [minx, maxx, miny, maxy] = this.getDimensions();
        this.x = minx + (maxx - minx) / 2;
        this.y = miny + (maxy - miny) / 2;
        // console.log('[Base] initControlPoints: ', this.points, this.x, this.y);
    }

    initUpdate(start, end) {
        if (!start || !end) return;
        // console.warn('[Base] initUpdate: ', this.name, start, end);
        // this.points[1] = _.cloneDeep(end);
        this.points[1] = { x: end.x, y: end.y };
        this.x = (parseInt(start.x) + parseInt(end.x)) / 2;
        this.y = (parseInt(start.y) + parseInt(end.y)) / 2;
    }
    update(i, pos) {
        // console.warn('[Base] update: ', i, pos, this.x, this.y);
        if (i === Infinity) {
            var that = this,
                x1 = pos.x - this.x,
                y1 = pos.y - this.y;
            // x1 = (pos.x - this.x) * this.ratio,
            // y1 = (pos.y - this.y) * this.ratio;
            this.points.forEach((p, i) => {
                that.points[i] = { x: parseInt(p.x) + parseInt(x1), y: parseInt(p.y) + parseInt(y1) };
            });
            this.x = Math.round(pos.x);
            this.y = Math.round(pos.y);
        } else {
            this.points[i] = pos;
            this.initControlPoints();
        }
    }
    // rotate(ang, pos) {
    //     if (!this.points || !this.points.length) return;
    //     this.points.forEach((p, i) => {
    //         let rp = new Point(p.x, p.y);
    //         let np = rp.rotate(pos, ang);
    //         p.x = np.x;
    //         p.y = np.y;
    //     });
    // }
    rotate(ang, pos, ori, oriCenter) {
        // console.error('Base.rotate:', this.name, ang, JSON.stringify(pos), JSON.stringify(ori));

        if (!this.points || !this.points.length) return;
        this.points.forEach((p, i) => {
            let x = ori[i].x - pos.x,
                y = ori[i].y - pos.y;
            let rp = new Point(x, y);
            // let rp = new Point(p.x, p.y);
            let np = rp.rotate(pos, ang);
            // let np = rp.rotate(ori[i], ang);
            p.x = parseInt(np.x);
            p.y = parseInt(np.y);
        });
        // if (this.name === GRAPH_TYPES.CIRCLE) {
        // 通过旋转之前的中心点来计算旋转之后的中心点，主要解决圆形计算中心点bug
        let x = oriCenter.x - pos.x,
            y = oriCenter.y - pos.y;
        let rp = new Point(x, y);
        // let rp = new Point(p.x, p.y);
        let np = rp.rotate(pos, ang);
        // let np = rp.rotate(ori[i], ang);
        this.x = parseInt(np.x);
        this.y = parseInt(np.y);
        // }
        // this.initControlPoints();
        return this;
    }

    updatePoints(i, pos) {
        // console.warn('[Base] updatePoints: ', i, pos, this.x, this.y);
        var that = this,
            x1 = pos.x - this.points[i].x,
            y1 = pos.y - this.points[i].y;
        // x1 = (pos.x - this.x) * this.ratio,
        // y1 = (pos.y - this.y) * this.ratio;
        this.points.forEach((p, i) => {
            that.points[i] = { x: parseInt(p.x) + x1, y: parseInt(p.y) + y1 };
        });

        this.initControlPoints();
    }
    createPath() {
        this.ctx.beginPath();
        // let lw = (1 / this.scaling) * 5 * this.ratio;
        // this.ctx.lineWidth = lw;
        this.points.forEach((p, i) => {
            this.ctx[i == 0 ? 'moveTo' : 'lineTo'](p.x, p.y);
        });
        this.ctx.closePath();
    }

    undo() {
        if (this.complete) return;
        this.points.pop();
        if (!this.points.length) this.complete = true;
    }

    /**
     * @param pos {x,y}
     * @returns -1: none, number: point index, Infinity: in path
     */
    isInPath(pos, scaling) {
        let idx = -1,
            r = (1 / scaling) * 5 * this.ratio;
        idx = this.points.findIndex(p => {
            this.ctx.beginPath();
            this.ctx.arc(p.x, p.y, r, 0, Math.PI * 2, false);
            return this.ctx.isPointInPath(pos.x, pos.y);
        });
        if (idx === -1) {
            // this.createPath();
            // if (this.ctx.isPointInPath(pos.x, pos.y)) idx = Infinity;
            this.ctx.beginPath();
            this.ctx.arc(this.x, this.y, r, 0, Math.PI * 2, false);
            if (this.ctx.isPointInPath(pos.x, pos.y)) idx = Infinity;
        }
        // console.warn('[Base] isInPath: ', idx, pos, this.points);
        return idx;
    }
    drawController(scaling) {
        if (scaling && scaling !== this.scaling) this.scaling = scaling;
        this.drawPoints(scaling);
        this.drawCenter(scaling);
    }
    drawPoints(scaling) {
        let w = 5,
            lineWidth = 2;
        if (scaling) {
            w = (1 / scaling) * 5;
            lineWidth = (1 / scaling) * 2;
        }
        // console.warn('[Base] drawPoints: ', this.name, w, lineWidth, this.points);
        // console.log('=======> ', w, lineWidth);
        this.ctx.save();
        this.ctx.lineWidth = lineWidth;
        this.ctx.strokeStyle = '#f00';
        // 最后一个点和第一个点相等时，去掉最后一个点 start 2020-12-07
        // let idx = this.points.length - 1,
        //     po = this.points[0],
        //     pos = this.points[idx],
        //     p0 = new Point(po.x, po.y),
        //     p1 = new Point(pos.x, pos.y);
        // if (this.points.length && this.points.length > 2 && p1.equals(p0)) {
        //     this.points.splice(this.points.length - 1, 1);
        // }
        // if (arcPolygon && this.points.length % 2 !== 0) {
        //     console.error('奇数');
        // } else {
        //     console.error('偶数');
        // }

        // 最后一个点和第一个点相等时，去掉最后一个点 end 2020-12-07
        this.points.forEach(p => {
            let y = this.isReverse ? -p.y : p.y;
            this.ctx.beginPath();
            this.ctx.arc(p.x, y, w, 0, Math.PI * 2, false);
            this.ctx.stroke();
        });
        this.ctx.restore();
    }
    setConnectIndexs(connectIndexs) {
        this.connectIndexs = connectIndexs;
    }
    drawUnConnectPoints() {
        let w = 5,
            lineWidth = 2;
        if (this.scaling) {
            w = (1 / this.scaling) * 5;
            lineWidth = (1 / this.scaling) * 2;
        }
        // console.warn('[Base] drawPoints: ', this.name, w, lineWidth, this.points);
        // console.log('=======> ', w, lineWidth);
        this.ctx.save();
        this.ctx.lineWidth = lineWidth;
        this.ctx.strokeStyle = '#f00';
        this.points.forEach((p, i) => {
            if (this.connectIndexs.indexOf(i) < 0) {
                let y = this.isReverse ? -p.y : p.y;
                this.ctx.beginPath();
                this.ctx.arc(p.x, y, w, 0, Math.PI * 2, false);
                this.ctx.stroke();
            }
        });
        // this.unConnectIndexs.forEach(p => {
        //     let y = this.isReverse ? -this.points[p].y : this.points[p].y;
        //     this.ctx.beginPath();
        //     this.ctx.arc(this.points[p].x, y, w, 0, Math.PI * 2, false);
        //     this.ctx.stroke();
        // });
        this.ctx.restore();
    }

    // eslint-disable-next-line no-unused-vars
    getAnchorPointIndex(pos) {
        return this.anchorIndex;
        // let idx = -1;
        // idx = this.points.findIndex(p => {
        //     return pos.equals(p);
        // });
        // return idx;
    }
    getAnchorPointWithCenterPoint(i, pos) {
        var x1 = pos.x - this.x,
            y1 = pos.y - this.y;
        return { x: parseInt(this.points[i].x) + x1, y: parseInt(this.points[i].y) + y1 };
    }

    setAnchorPointIndex(anchorIndex) {
        this.anchorIndex = anchorIndex;
        // if (this.unConnectIndexs && this.unConnectIndexs.length) {
        //     let idx = this.unConnectIndexs.findIndex(p => {
        //         return (p = anchorIndex);
        //     });
        //     this.unConnectIndexs.splice(idx, 1);
        // }
    }
    drawAnchorPoint(scaling) {
        if (this.anchorIndex < 0) return;
        // console.warn('Base.drawAnchorPoint: ', this.anchorIndex, this.scaling);
        let w = this.lineWidth,
            lineWidth = this.lineWidth / 5;
        if (scaling) {
            w = (1 / scaling) * 8;
            lineWidth = (1 / scaling) * 5;
        }
        // console.warn('[Base] drawPoints: ', this.name, w, lineWidth, this.points);
        // console.log('=======> ', w, lineWidth);
        this.ctx.save();
        this.ctx.lineWidth = lineWidth;
        this.ctx.strokeStyle = '#f00';
        this.ctx.fillStyle = '#f00';
        let y = this.isReverse ? -this.points[this.anchorIndex].y : this.points[this.anchorIndex].y;
        this.ctx.beginPath();
        this.ctx.moveTo(this.points[this.anchorIndex].x, y);
        this.ctx.arc(this.points[this.anchorIndex].x, y, w, 0, Math.PI * 2, false);
        this.ctx.stroke();
        this.ctx.fill();
        this.ctx.restore();
    }
    drawCenter(scaling) {
        let lw = scaling ? (1 / scaling) * 2 : 2,
            r = scaling ? (1 / scaling) * 10 : 10;
        this.ctx.save();
        this.ctx.lineWidth = lw;
        this.ctx.strokeStyle = 'rgba(238,153,34,1)';
        this.ctx.fillStyle = 'rgba(238,153,34,0.8)';
        this.ctx.beginPath();
        let y = this.isReverse ? -this.y : this.y;
        this.ctx.arc(this.x, y, r, 0, Math.PI * 2, false);
        this.ctx.stroke();
        this.ctx.fill();
        this.ctx.restore();
        // console.log('[Base] drawCenter: ', this.x, this.y);
    }
    draw(ctx) {
        if (ctx) this.ctx = ctx;

        this.ctx.save();
        this.ctx.lineWidth = this.lineWidth;
        this.ctx.strokeStyle = this.strokeStyle;
        this.ctx.fillStyle = this.fillStyle;
        this.createPath();
        this.ctx.stroke();
        if (this.isFill) {
            this.ctx.fill();
        }
        this.ctx.restore();
    }

    /**
     * Return the dimensions of the Graph, means min/max xy of location points.
     * [minx, maxx, miny, maxy]
     */
    getDimensions() {
        let dms = [],
            ratio = 1;
        if (!this.points || !this.points.length) return dms;
        // if (this.name === GRAPH_TYPES.CIRCLE) {
        //     dms = [
        //         (this.x - this.radius) * ratio,
        //         (this.x + this.radius) * ratio,
        //         (this.y - this.radius) * ratio,
        //         (this.y + this.radius) * ratio
        //     ];
        //     return dms;
        // }
        let op = this.points[0];
        dms = this.points.reduce(
            (pre, p) => [Math.min(pre[0], p.x), Math.max(pre[1], p.x), Math.min(pre[2], p.y), Math.max(pre[3], p.y)],
            [op.x, op.x, op.y, op.y]
        );
        return dms;
    }

    // 获取两点连线的长度
    getLineLength(p1, p2) {
        let stp = new Point(p1.x, p1.y);
        let distance = stp.distance(p2);
        if (distance > 100) distance = (distance / 1000).toFixed(2) + 'm';
        else distance = parseInt(distance) + 'mm';
        return distance;
    }
    // 获取两点中间点
    getLineMiddlePoint(p1, p2) {
        let stp = new Point(p1.x, p1.y);
        let middlePoint = stp.middle(p2);
        return middlePoint;
    }
}
